<?php

namespace seecms;

use Psr\Cache\InvalidArgumentException;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\CacheItem;

class SeeCache implements CacheInterface
{
    /**
     * @var FilesystemAdapter
     */
    protected $filesystem = null;

    /**
     * @var SeeConfig|null
     */
    protected static $instance = null;

    /**
     * @var array
     */
    protected $config = [];

    protected function __construct()
    {

    }

    protected function __clone()
    {

    }

    /**
     * @return SeeCache
     */
    public static function instance(): SeeCache
    {
        if (is_null(self::$instance)) {
            $config = See::config()->cache;
            $instance = new self();
            $instance->filesystem = new FilesystemAdapter($config->name(), $config->expire(), $config->path());
            self::$instance = $instance;
        }

        return self::$instance;
    }

    /**
     * @param $key
     * @return string
     */
    protected function key($key): string
    {
        return See::config()->cache->prefix() . $key;
    }

    /**
     * @param $key
     * @param $default
     * @return mixed|null
     */
    public function get($key, $default = null)
    {

        $value = null;
        try {
            /**
             * @var CacheItem $item
             */
            $item = $this->filesystem->getItem($this->key($key));
            $value = $item->get();
        } catch (InvalidArgumentException $exception) {

        }

        return $value === null ? $default : $value;
    }

    /**
     * @throws InvalidArgumentException
     */
    public function set($key, $value, $ttl = null): bool
    {
        /**
         * @var CacheItem $item
         */
        $item = $this->filesystem->getItem($this->key($key));
        $item->set($value);
        if ($ttl) {
            $item->expiresAfter($ttl);
        }
        $this->filesystem->save($item);

        return true;
    }

    public function delete($key): bool
    {
        $result = false;
        try {
            $result = $this->filesystem->delete($this->key($key));
        } catch (InvalidArgumentException $exception) {

        }

        return $result;
    }

    public function clear()
    {
        $this->filesystem->clear();
    }

    public function getMultiple($keys, $default = null): array
    {
        $result = [];

        foreach ($keys as $key) {
            $result[$key] = $this->get($this->key($key), $default);
        }

        return $result;
    }

    /**
     * @throws InvalidArgumentException
     */
    public function setMultiple($values, $ttl = null): bool
    {
        foreach ($values as $key => $val) {

            $result = $this->set($this->key($key), $val, $ttl);

            if (false === $result) {
                return false;
            }
        }

        return true;
    }

    public function deleteMultiple($keys): bool
    {
        foreach ($keys as $key) {

            $result = $this->delete($this->key($key));

            if (false === $result) {
                return false;
            }
        }

        return true;
    }

    public function has($key): bool
    {
        $result = false;
        try {
            $result = $this->filesystem->hasItem($this->key($key));
        } catch (InvalidArgumentException $exception) {

        }

        return $result;
    }
}